
<!DOCTYPE html>
<html lang="zh">
<head>
    <meta charset="UTF-8">
    <title>俄罗斯方块</title>
    <meta name="renderer" content="webkit">
    <meta http-equiv="X-UA-Compatible" content="IE=edge,chrome=1">
    <meta name="viewport" content="width=device-width, initial-scale=1, maximum-scale=1">
    <style>
        body {
            display: flex;
            justify-content: center;
            align-items: center;
            height: 100vh;
            margin: 0;
            background-color: #f0f0f0;
            font-family: Arial, sans-serif;
        }
        .game-container {
            display: flex;
            gap: 30px;
            padding: 30px;
            background-color: #fff;
            border-radius: 15px;
            box-shadow: 0 0 20px rgba(0,0,0,0.1);
            transform: scale(1.2);
            transform-origin: center center;
        }
        canvas {
            border: 3px solid #333;
        }
        .info-panel {
            width: 200px;
            padding: 20px;
            background-color: #f8f8f8;
            border-radius: 10px;
            font-size: 1.2em;
        }
        .info-panel div {
            margin-bottom: 20px;
        }
        .preview-canvas {
            border: 1px solid #666;
        }
    </style>
</head>
<body>
    <div class="game-container">
        <canvas id="gameCanvas" width="300" height="600"></canvas>
        <div class="info-panel">
            <div>
                <h3>分数: <span id="score">0</span></h3>
            </div>
            <div>
                <h3>下一个:</h3>
                <canvas id="previewCanvas" width="100" height="100"></canvas>
            </div>
            <div>
                <h3>操作说明:</h3>
                <p>↑ 旋转</p>
                <p>↓ 加速下落</p>
                <p>← → 左右移动</p>
                <p>空格 暂停</p>
            </div>
        </div>
    </div>
    <script>
        class Tetris {
            constructor() {
                this.canvas = document.getElementById('gameCanvas');
                this.ctx = this.canvas.getContext('2d');
                this.previewCanvas = document.getElementById('previewCanvas');
                this.previewCtx = this.previewCanvas.getContext('2d');
                this.blockSize = 30;
                this.cols = this.canvas.width / this.blockSize;
                this.rows = this.canvas.height / this.blockSize;
                this.grid = Array(this.rows).fill().map(() => Array(this.cols).fill(0));
                this.score = 0;
                this.gameOver = false;
                this.paused = false;
                
                // 方块形状定义
                this.shapes = {
                    I: [[1,1,1,1]],
                    L: [[1,0],[1,0],[1,1]],
                    J: [[0,1],[0,1],[1,1]],
                    O: [[1,1],[1,1]],
                    Z: [[1,1,0],[0,1,1]],
                    S: [[0,1,1],[1,1,0]],
                    T: [[0,1,0],[1,1,1]]
                };
                
                this.colors = {
                    I: '#00f0f0',
                    L: '#f0a500',
                    J: '#0000f0',
                    O: '#f0f000',
                    Z: '#f00000',
                    S: '#00f000',
                    T: '#a000f0'
                };
                
                this.currentPiece = this.newPiece();
                this.nextPiece = this.newPiece();
                this.dropCounter = 0;
                this.dropInterval = 1000;
                this.lastTime = 0;
                
                this.bindEvents();
                this.update();
            }
            
            newPiece() {
                const pieces = 'ILJOZST';
                const type = pieces[Math.floor(Math.random() * pieces.length)];
                const shape = this.shapes[type];
                return {
                    type,
                    shape: shape,
                    pos: {x: Math.floor(this.cols/2) - Math.floor(shape[0].length/2), y: 0},
                    color: this.colors[type]
                };
            }
            
            rotate(matrix) {
                const N = matrix.length;
                const M = matrix[0].length;
                let result = Array(M).fill().map(() => Array(N).fill(0));
                for(let i = 0; i < N; i++) {
                    for(let j = 0; j < M; j++) {
                        result[j][N-1-i] = matrix[i][j];
                    }
                }
                return result;
            }
            
            isValidMove(piece, offsetX, offsetY, newShape = null) {
                const shape = newShape || piece.shape;
                for(let y = 0; y < shape.length; y++) {
                    for(let x = 0; x < shape[y].length; x++) {
                        if(shape[y][x]) {
                            const newX = piece.pos.x + x + offsetX;
                            const newY = piece.pos.y + y + offsetY;
                            if(newX < 0 || newX >= this.cols || newY >= this.rows) return false;
                            if(newY >= 0 && this.grid[newY][newX]) return false;
                        }
                    }
                }
                return true;
            }
            
            merge() {
                this.currentPiece.shape.forEach((row, y) => {
                    row.forEach((value, x) => {
                        if(value) {
                            const newY = this.currentPiece.pos.y + y;
                            const newX = this.currentPiece.pos.x + x;
                            if(newY >= 0) {
                                this.grid[newY][newX] = this.currentPiece.color;
                            }
                        }
                    });
                });
            }
            
            clearLines() {
                let linesCleared = 0;
                outer: for(let y = this.rows - 1; y >= 0; y--) {
                    for(let x = 0; x < this.cols; x++) {
                        if(!this.grid[y][x]) continue outer;
                    }
                    
                    const row = this.grid.splice(y, 1)[0];
                    this.grid.unshift(row.fill(0));
                    y++;
                    linesCleared++;
                }
                
                if(linesCleared > 0) {
                    this.score += [40, 100, 300, 1200][linesCleared - 1];
                    document.getElementById('score').textContent = this.score;
                }
            }
            
            drop() {
                if(!this.isValidMove(this.currentPiece, 0, 1)) {
                    this.merge();
                    this.clearLines();
                    if(this.currentPiece.pos.y <= 0) {
                        this.gameOver = true;
                        alert('游戏结束！最终得分：' + this.score);
                        return;
                    }
                    this.currentPiece = this.nextPiece;
                    this.nextPiece = this.newPiece();
                    this.drawPreview();
                } else {
                    this.currentPiece.pos.y++;
                }
                this.dropCounter = 0;
            }
            
            draw() {
                // 清空画布
                this.ctx.fillStyle = '#fff';
                this.ctx.fillRect(0, 0, this.canvas.width, this.canvas.height);
                
                // 绘制网格
                this.grid.forEach((row, y) => {
                    row.forEach((value, x) => {
                        if(value) {
                            this.ctx.fillStyle = value;
                            this.ctx.fillRect(x * this.blockSize, y * this.blockSize, 
                                           this.blockSize - 1, this.blockSize - 1);
                        }
                    });
                });
                
                // 绘制当前方块
                this.currentPiece.shape.forEach((row, y) => {
                    row.forEach((value, x) => {
                        if(value) {
                            this.ctx.fillStyle = this.currentPiece.color;
                            this.ctx.fillRect(
                                (this.currentPiece.pos.x + x) * this.blockSize,
                                (this.currentPiece.pos.y + y) * this.blockSize,
                                this.blockSize - 1,
                                this.blockSize - 1
                            );
                        }
                    });
                });
            }
            
            drawPreview() {
                this.previewCtx.fillStyle = '#fff';
                this.previewCtx.fillRect(0, 0, this.previewCanvas.width, this.previewCanvas.height);
                
                const offsetX = (this.previewCanvas.width - this.nextPiece.shape[0].length * 20) / 2;
                const offsetY = (this.previewCanvas.height - this.nextPiece.shape.length * 20) / 2;
                
                this.nextPiece.shape.forEach((row, y) => {
                    row.forEach((value, x) => {
                        if(value) {
                            this.previewCtx.fillStyle = this.nextPiece.color;
                            this.previewCtx.fillRect(
                                offsetX + x * 20,
                                offsetY + y * 20,
                                19,
                                19
                            );
                        }
                    });
                });
            }
            
            bindEvents() {
                document.addEventListener('keydown', (e) => {
                    if(this.gameOver) return;
                    
                    if(e.key === ' ') {
                        this.paused = !this.paused;
                        return;
                    }
                    
                    if(this.paused) return;
                    
                    switch(e.key) {
                        case 'ArrowLeft':
                            if(this.isValidMove(this.currentPiece, -1, 0)) {
                                this.currentPiece.pos.x--;
                            }
                            break;
                        case 'ArrowRight':
                            if(this.isValidMove(this.currentPiece, 1, 0)) {
                                this.currentPiece.pos.x++;
                            }
                            break;
                        case 'ArrowDown':
                            this.drop();
                            break;
                        case 'ArrowUp':
                            const rotated = this.rotate(this.currentPiece.shape);
                            if(this.isValidMove(this.currentPiece, 0, 0, rotated)) {
                                this.currentPiece.shape = rotated;
                            }
                            break;
                    }
                });
            }
            
            update(time = 0) {
                if(!this.lastTime) this.lastTime = time;
                const deltaTime = time - this.lastTime;
                this.lastTime = time;
                
                if(!this.gameOver && !this.paused) {
                    this.dropCounter += deltaTime;
                    if(this.dropCounter > this.dropInterval) {
                        this.drop();
                    }
                }
                
                this.draw();
                requestAnimationFrame(this.update.bind(this));
            }
        }

        // 启动游戏
        window.onload = () => {
            new Tetris();
        };
    </script>
</body>
</html>